package org.liang.common.utils.date;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

/**
 * 日期工具类（String 类型）.
 * 
 * @author L.Yang
 * @version 1.0, 2014-7-9
 */
public final class DateUtil {

    /** 构造方法私有化. */
    private DateUtil() {}

    /**
     * 根据传入的日期格式 获取系统的前一天时间.
     * 
     * @param pattern
     *            日期格式 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 系统的前一天时间
     */
    public static String getPreviousDate(String pattern) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.add(Calendar.DAY_OF_MONTH, -1);
        return DateBase.formatDate(cal, pattern);
    }

    /**
     * 根据传入的日期格式 获取当前系统时间.
     * 
     * @param pattern
     *            日期格式 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 对应格式的当前系统时间
     */
    public static String getCurrentDate(String pattern) {
        return DateBase.formatDate(GregorianCalendar.getInstance(), pattern);
    }

    /**
     * 根据传入的日期格式 获取系统的明天时间.
     * 
     * @param pattern
     *            日期格式 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 系统的明天时间
     */
    public static String getNextDate(String pattern) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.add(Calendar.DAY_OF_MONTH, 1);
        Date date = cal.getTime();
        return DateBase.formatDate(date, pattern);
    }

    /**
     * 获取指定日期的前或后推N天（字符串类型），如果传入的参数为空，则返回空.
     * 
     * @param date
     *            日期
     * @param days
     *            跳转天数 负数就是往前推，正数即往后推
     * @param pattern
     *            日期的格式 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 返回字符型日期
     */
    public static String moveDays(String date, int days, String pattern) {
        if (days == 0) {
            return date;
        }
        if (date == null || date.trim().equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        Date tmp = DateBase.parseDate(date, pattern);
        return DateBase.formatDate(DateBase.addDays(tmp, days), pattern);
    }

    /**
     * 获取指定日期的前或后推N月（字符串类型），如果传入的参数为空，则返回空.
     * 
     * @param date
     *            日期
     * @param months
     *            跳转月数 负数就是往前推，正数即往后推
     * @param pattern
     *            日期的格式 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 返回字符型日期
     */
    public static String moveMonths(String date, int months, String pattern) {
        if (months == 0) return date;
        if (date == null || date.trim().equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        Date tmp = DateBase.parseDate(date, pattern);
        return DateBase.formatDate(DateBase.addMonths(tmp, months), pattern);
    }

    /**
     * 返回指定日期和其后n天日期list.
     * 
     * @param date
     *            日期
     * @param days
     *            天数 负数就是往前推，正数即往后推
     * @param pattern
     *            格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 日期集合
     */
    public static List<String> getDates(String date, int days, String pattern) {
        String toDate = moveDays(date, days, pattern);
        return getDates(date, toDate, pattern);
    }

    /**
     * 取得两个日期之间的所有日期集合，包含起始日期和结束日期， 日期不分前后顺序，支持跨年.
     * 
     * @param dateO
     *            起始日期
     * @param dateT
     *            结束日期
     * @param pattern
     *            格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 日期集合
     */
    public static List<String> getDates(String dateO, String dateT, String pattern) {
        if ((dateO == null) || (dateT == null) || dateO.trim().equals("")
            || dateT.trim().equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        List<String> list = new ArrayList<String>();
        Date dateOne = DateBase.parseDate(dateO, pattern);
        Date dateTwo = DateBase.parseDate(dateT, pattern);
        Calendar calO = GregorianCalendar.getInstance();
        Calendar calT = GregorianCalendar.getInstance();
        if (dateOne.after(dateTwo)) {
            calO.setTime(dateTwo);
            calT.setTime(dateOne);
        } else {
            calO.setTime(dateOne);
            calT.setTime(dateTwo);
        }
        while (!calO.after(calT)) {
            list.add(DateBase.formatDate(calO, pattern));
            calO.add(GregorianCalendar.DATE, +1);
        }
        return list;
    }

    /**
     * 获取两个日期之间的天数， 日期不分前后顺序，支持跨年.
     * 
     * @param dateO
     *            日期1
     * @param dateT
     *            日期2
     * @param pattern
     *            格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 两个日期之间的天数
     */
    public static int getDayCountBetween2Days(String dateO, String dateT, String pattern) {
        if ((dateO == null) || (dateT == null) || dateO.trim().equals("")
            || dateT.trim().equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        int count = 0;
        Date dateOne = DateBase.parseDate(dateO, pattern);
        Date dateTwo = DateBase.parseDate(dateT, pattern);
        Calendar calO = GregorianCalendar.getInstance();
        Calendar calT = GregorianCalendar.getInstance();
        if (dateOne.after(dateTwo)) {
            calO.setTime(dateTwo);
            calT.setTime(dateOne);
        } else {
            calO.setTime(dateOne);
            calT.setTime(dateTwo);
        }
        while (!calO.after(calT)) {
            count++;
            calO.add(GregorianCalendar.DATE, +1);
        }
        return count;
    }

    /**
     * 获取传入日期的同类型日， 正数为未来周中，负数为历史周中.
     * 
     * @param date
     *            传入日期
     * @param weeks
     *            正数为未来周中，负数为历史周中
     * @param pattern
     *            日期的格式 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 同类型日
     */
    public static String getSimilarDate(String date, int weeks, String pattern) {
        if (weeks == 0) return date;
        if (date == null || date.equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        Date tmp = DateBase.parseDate(date, pattern);
        return DateBase.formatDate(DateBase.addWeeks(tmp, weeks), pattern);
    }

    /**
     * 获取一段时间内，对应日期的所有同类型日 日期不分前后顺序，支持跨年.
     * 
     * @param dateO
     *            日期1
     * @param dateT
     *            日期2
     * @param dayOfWeek
     *            目标日期
     * @param pattern
     *            目标日期格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 目标日期的同类型日列表（pattern格式）
     */
    public static List<String> getSimilarDates(String dateO, String dateT, String dayOfWeek,
                                                     String pattern) {
        if ((null == dateO) || (null == dateT) || (null == dayOfWeek) || dateO.trim().equals("")
            || dateT.trim().equals("") || dayOfWeek.trim().equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        Date targetDate = DateBase.parseDate(dayOfWeek, pattern);
        int target = DateBase.getDayOfWeek(targetDate);
        return getSimilarDates(dateO, dateT, target, pattern);
    }

    /**
     * 获取一段时间内，对应日期的所有同类型日 日期不分前后顺序，支持跨年.
     * 
     * @param dateO
     *            日期1
     * @param dateT
     *            日期2
     * @param dayOfWeek
     *            目标日期 Calendar.DAY_OF_WEEK;
     * @param pattern
     *            格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 目标日期的同类型日列表（pattern格式）
     */
    public static List<String> getSimilarDates(String dateO, String dateT, int dayOfWeek,
                                                     String pattern) {
        if ((null == dateO) || (null == dateT) || dateO.trim().equals("")
            || dateT.trim().equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        if (0 == dayOfWeek) {
            throw new IllegalArgumentException("目标日起录入错误，目标日期为 1~7 的整数");
        }

        List<String> list = new ArrayList<String>();
        try {
            Date dateOne = DateBase.parseDate(dateO, pattern);
            Date dateTwo = DateBase.parseDate(dateT, pattern);
            Calendar calO = GregorianCalendar.getInstance();
            Calendar calT = GregorianCalendar.getInstance();
            if (dateOne.after(dateTwo)) {
                calO.setTime(dateTwo);
                calT.setTime(dateOne);
            } else {
                calO.setTime(dateOne);
                calT.setTime(dateTwo);
            }
            while (!calO.after(calT)) {
                if (calO.get(Calendar.DAY_OF_WEEK) == dayOfWeek) {
                    list.add(DateBase.formatDate(calO, pattern));
                }
                calO.add(GregorianCalendar.DATE, +1);
            }
        } catch (Exception e) {
            return list;
        }
        return list;
    }

    /**
     * 获取一段时间内，所有双休日 日期不分前后顺序，支持跨年.
     * 
     * @param dateO
     *            日期1
     * @param dateT
     *            日期2
     * @param pattern
     *            格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 所有双休日列表
     */
    public static List<String> getWeekends(String dateO, String dateT, String pattern) {
        return getDatesInWeek(dateO, dateT, pattern, DAY_TYPE_WEEKEND);
    }

    /**
     * 获取一段时间内，所有工作日 日期不分前后顺序，支持跨年.
     * 
     * @param dateO
     *            日期1
     * @param dateT
     *            日期2
     * @param pattern
     *            格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @return 所有工作日列表
     */
    public static List<String> getWorkdays(String dateO, String dateT, String pattern) {
        return getDatesInWeek(dateO, dateT, pattern, DAY_TYPE_WORKDAY);
    }

    /** 工作日. */
    private static final String DAY_TYPE_WORKDAY = "workday";

    /** 周末. */
    private static final String DAY_TYPE_WEEKEND = "weekend";

    /**
     * 获取一段时间内，所有双休日 日期不分前后顺序，支持跨年.
     * 
     * @param dateO
     *            日期1
     * @param dateT
     *            日期2
     * @param pattern
     *            格式化字符串 如果传入格式为空，则为默认格式 yyyy-MM-dd
     * @param type
     *            日期类型 -- DAY_TYPE_WORKDAY（工作日）、 DAY_TYPE_WEEKEND（周末）
     * @return pattern格式的日期列表
     */
    private static List<String> getDatesInWeek(String dateO, String dateT,
                                               String pattern, String type) {
        if ((null == dateO) || (null == dateT) || dateO.trim().equals("")
            || dateT.trim().equals("")) {
            throw new IllegalArgumentException("传入的日期不能为空！");
        }
        List<String> list = new ArrayList<String>();
        try {
            Date dateOne = DateBase.parseDate(dateO, pattern);
            Date dateTwo = DateBase.parseDate(dateT, pattern);
            Calendar calO = GregorianCalendar.getInstance();
            Calendar calT = GregorianCalendar.getInstance();
            if (dateOne.after(dateTwo)) {
                calO.setTime(dateTwo);
                calT.setTime(dateOne);
            } else {
                calO.setTime(dateOne);
                calT.setTime(dateTwo);
            }
            while (!calO.after(calT)) {
                if (type.equalsIgnoreCase(DAY_TYPE_WEEKEND)) {
                    if ((calO.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
                        || (calO.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)) {
                        list.add(DateBase.formatDate(calO, pattern));
                    }
                } else if (type.equalsIgnoreCase(DAY_TYPE_WORKDAY)) {
                    if ((calO.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)
                        && (calO.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY)) {
                        list.add(DateBase.formatDate(calO, pattern));
                    }
                }
                calO.add(GregorianCalendar.DATE, +1);
            }
        } catch (Exception e) {
            return list;
        }
        return list;
    }

}
